/**
 * File    : OpenIDAuthenticationManagerImpl.java
 * Created : 2008-10-5
 * By      : LuHuiguo
 */
package com.luhuiguo.sso.service.impl;

import java.net.MalformedURLException;
import java.net.URL;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Required;

import com.luhuiguo.sso.entity.Approval;
import com.luhuiguo.sso.entity.AuthAction;
import com.luhuiguo.sso.entity.User;
import com.luhuiguo.sso.exception.IdentifierViolationException;
import com.luhuiguo.sso.exception.InvalidRequestException;
import com.luhuiguo.sso.exception.SiteDisallowedException;
import com.luhuiguo.sso.provider.OpenIDAuthRequest;
import com.luhuiguo.sso.provider.OpenIDAuthResponse;
import com.luhuiguo.sso.service.ActivityManager;
import com.luhuiguo.sso.service.ApprovalManager;
import com.luhuiguo.sso.service.OpenIDAuthenticationManager;
import com.luhuiguo.sso.service.PropertyManager;
import com.luhuiguo.sso.service.UserManager;

/**
 * @author LuHuiguo
 * @version $Id: OpenIDAuthenticationManagerImpl.java 7 2008-10-06 03:46:38Z
 *          LuHuiguo $
 * 
 */
public class OpenIDAuthenticationManagerImpl implements
		OpenIDAuthenticationManager {

	private UserManager userManager;

	private PropertyManager propertyManager;

	private ActivityManager activityManager;

	private ApprovalManager approvalManager;

	@Required
	public void setUserManager(UserManager userManager) {
		this.userManager = userManager;
	}

	@Required
	public void setPropertyManager(PropertyManager propertyManager) {
		this.propertyManager = propertyManager;
	}

	@Required
	public void setActivityManager(ActivityManager activityManager) {
		this.activityManager = activityManager;
	}

	@Required
	public void setApprovalManager(ApprovalManager approvalManager) {
		this.approvalManager = approvalManager;
	}

	@Override
	public OpenIDAuthResponse allowRequest(User user, long personaId,
			OpenIDAuthRequest authReq, boolean alwaysAllow) {
		OpenIDAuthResponse response;
		try {

			Approval approval = approvalManager.setApproval(user, authReq
					.getReturnToURL(), personaId, alwaysAllow);

			activityManager.createActivity(user, approval.getSite(),
					alwaysAllow ? AuthAction.ALLOW_ALWAYS
							: AuthAction.ALLOW_ONCE);

			response = new OpenIDAuthResponse(authReq.getIdentifier(), true);

			response.setAttributes(approval.getPersona().getAttributesAsMap());

		} catch (Exception e) {
			response = new OpenIDAuthResponse(authReq.getIdentifier(), false);
		}
		return response;
	}

	@Override
	public OpenIDAuthResponse autoAllowRequest(User user,
			OpenIDAuthRequest authReq) {
		Approval approval = approvalManager.getApproval(user, authReq
				.getReturnToURL());
		OpenIDAuthResponse response;
		if (approval != null && approval.isAlwaysAllow()) {
			activityManager.createActivity(user, approval.getSite(),
					AuthAction.ALLOW_ALWAYS_AUTO);
			response = new OpenIDAuthResponse(authReq.getIdentifier(), true);
			response.setAttributes(approval.getPersona().getAttributesAsMap());
		} else {
			response = new OpenIDAuthResponse(authReq.getIdentifier(), false);
		}
		return response;
	}

	@Override
	public OpenIDAuthResponse checkImmediate(String username,
			OpenIDAuthRequest authReq) {
		try {
			User user = userManager.getUser(username);
			validateRequest(user, authReq);
			return autoAllowRequest(user, authReq);
		} catch (Exception e) {
			return new OpenIDAuthResponse(authReq.getIdentifier(), false);
		}
	}

	@Override
	public OpenIDAuthResponse denyRequest(User user, OpenIDAuthRequest authReq) {

		activityManager.createActivity(user, authReq.getReturnToURL(),
				AuthAction.DENY);
		return new OpenIDAuthResponse(authReq.getIdentifier(), false);
	}

	@Override
	public void validateRequest(User user, OpenIDAuthRequest authReq)
			throws InvalidRequestException, SiteDisallowedException,
			IdentifierViolationException {
		if (authReq == null)
			throw new InvalidRequestException(
					"Authentication request not found");
		URL authenticatingHost = null;
		try {
			authenticatingHost = new URL(authReq.getReturnToURL());
		} catch (MalformedURLException e) {
			throw new InvalidRequestException(
					"Malformed return_to URL in OpenID request", e);
		}
		String username = authReq.getIdentifier().replaceFirst(".*/", "");
		if (!username.equals(user.getUsername()))
			throw new IdentifierViolationException((new StringBuilder())
					.append("User ").append(user.getUsername()).append(
							" cannot verify another user's OpenID: ").append(
							authReq.getIdentifier()).toString());
		if (!propertyManager.isEnableStatelessMode()
				&& !authReq.hasAssocHandle())
			throw new SiteDisallowedException(
					"Site is making a stateless authentication request. This has been disabled by your administrator");
		// if (!siteManager.isSiteAllowedToAuthenticate(authenticatingHost))
		// throw new SiteDisallowedException(
		// (new StringBuilder())
		// .append(
		// "Site has been globally disallowed by blacklist/whitelist: ")
		// .append(authenticatingHost).toString());
		if (StringUtils.contains(authenticatingHost.getHost(), "localhost")
				|| StringUtils.contains(authenticatingHost.getHost(),
						"127.0.0.1"))
			if (!propertyManager.isEnableRelyingPartyLocalhostMode())
				throw new SiteDisallowedException((new StringBuilder()).append(
						"Localhost relying-parties have been disallowed: ")
						.append(authenticatingHost).toString());

	}

}
